package org.metasketch.diagram.javafx.graphics;

import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.text.TextAlignment;

import org.metasketch.editor.timeline.SnapshotManager;
import org.metasketch.javafx.graphics.IJFXGraphicNode;
import org.metasketch.model.CommonIdentified;
import org.metasketch.reflection.RefUtil;

public class CustomLabel extends Group implements EventHandler<MouseEvent> {

	RefUtil util = new RefUtil();
	String fieldName;
	String writeScript;
	String readScript;
	// boolean alertChanges = false;

	TextField textField = new TextField();

	boolean editable = false;

	int width = 60;
	int height = 10;

	int padding = 5;
	Label label = new Label();

	IJFXGraphicNode graphic;
	boolean verticallyCentered = true;
	boolean horizontallyCentered = true;

	String leftPadding;
	String rightPadding;
	String topPadding;
	String bottomPadding;

	protected int getPadding(String padding, int side) {
		if (padding == null)
			return 0;
		// int pad = 0;
		if (padding.contains("%")) {
			String ratio = padding.substring(0, padding.indexOf('%'));
			Double r = Double.valueOf(ratio);
			double pad = side * r;
			return (int) pad;
		} else {
			try {
				int pad = Integer.valueOf(padding);
				return pad;
			} catch (Throwable t) {

			}
		}
		return 0;
	}

	public CustomLabel() {
		initialSetup();
	}

	public CustomLabel(String string) {
		label.setText(string);
		textField.setText(string);

		// textField.toFront();
		//
		// textField.setPrefColumnCount(20);

		initialSetup();
	}

	// public void setupField(String fieldName) {
	// this.fieldName = fieldName;
	// }

	private void initialSetup() {

		textField.setText("WTF!!!");

		textField.setEditable(true);
		textField.toFront();
		// textField
		// .setStyle("-fx-background-color: red; -fx-fill: red; -fx-stroke: gray;  -fx-stroke-type: outside;  -fx-stroke-width: 5;   -fx-stroke-dash-array: 12 2 4 2;    -fx-stroke-dash-offset: 6;     -fx-stroke-line-cap: butt; -fx-opacity: 0.5;");
		textField.setVisible(false);

		// textField.setStyle("-fx-background-color: white;");
		// textField.setStroke(Color.BLACK);
		// textField.setStrokeWidth(2);
		// textField.setMinWidth(100);
		// textField.setPrefWidth(100);
		// textField.setMinHeight(20);
		// textField.setPrefHeight(20);
		// textField.set

		label.setTextAlignment(TextAlignment.CENTER);
		label.setAlignment(Pos.BASELINE_CENTER);
		label.setWrapText(true);

		// setStyle("-fx-fill: red;");

		label.setOnMouseClicked(this);

		getChildren().addAll(label, textField);

		textField.setOnKeyReleased(new EventHandler<KeyEvent>() {

			@Override
			public void handle(KeyEvent event) {

				if (!editable) {
					event.consume();
					return;
				}

				// System.out.println(event);

				if (event.getCode() == KeyCode.ESCAPE) {

					label.setVisible(true);
					textField.setVisible(false);

					// getChildren().remove(textField);

					event.consume();
				} else if (event.getCode() == KeyCode.ENTER) {

					String changedText = textField.getText();

					label.setText(changedText);

					CommonIdentified object = graphic.getSemantic();

					if (writeScript != null) {

						Binding binding = new Binding();
						binding.setVariable("semantic", object);
						// binding.setVariable("label", label);
						binding.setVariable("text", changedText);
						GroovyShell shell = new GroovyShell(binding);

						shell.evaluate(writeScript);

						// if (value instanceof String)
						// util.setValue(object, fieldName, changedText);

						graphic.alertModelChanged();

						SnapshotManager.takeSnapshot();

					} else if (fieldName != null) {

						try {
							util.setValue(object, fieldName, changedText);
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}

						graphic.alertModelChanged();

						SnapshotManager.takeSnapshot();

					}

					label.setVisible(true);
					// getChildren().remove(textField);
					textField.setVisible(false);

					event.consume();
				}

				// event.consume();
			}

		});
	}

	public void resize() {

		if (graphic instanceof BaseGraphic) {

			BaseGraphic baseGraphic = (BaseGraphic) graphic;

			label.setTranslateX(padding
					+ getPadding(leftPadding, baseGraphic.getWidth()));
			label.setTranslateY(padding
					+ getPadding(topPadding, baseGraphic.getHeight()));

			int doublePadding = padding * 2;
			// int doublePadding = padding;

			if (horizontallyCentered) {
				int pad = doublePadding
						+ getPadding(rightPadding, baseGraphic.getWidth());
				label.setMaxWidth(baseGraphic.getWidth() - pad);
				label.setPrefWidth(baseGraphic.getWidth() - pad);
			} else {
				label.setMaxWidth(width);
				label.setPrefWidth(width);
			}

			if (verticallyCentered) {
				int pad = doublePadding
						+ getPadding(bottomPadding, baseGraphic.getHeight());
				label.setMaxHeight(baseGraphic.getHeight() - pad);
				label.setPrefHeight(baseGraphic.getHeight() - pad);
			} else {
				label.setMaxHeight(height);
				label.setPrefHeight(height);
			}

			textField.setTranslateY(padding);
			textField.setTranslateX(padding);

		}

		// textField.setMaxWidth(padding);
		// textField.setPrefHeight(padding);
	}

	public IJFXGraphicNode getGraphic() {
		return graphic;
	}

	public void setGraphic(IJFXGraphicNode baseGraphic) {
		this.graphic = baseGraphic;
		// baseGraphic.getChildren().add(this);
		resize();
	}

	public int getPadding() {
		return padding;
	}

	public void setPadding(int padding) {
		this.padding = padding;
		resize();
	}

	// public void setCenteredVertically(boolean centered) {
	// verticallyCentered = centered;
	// }
	//
	// public void setCenteredHorizontally(boolean centered) {
	// horizontallyCentered = centered;
	// }

	public void setTextVerticalCentered() {
		label.setAlignment(Pos.BASELINE_CENTER);
	}

	public void setTextVerticalTop() {
		label.setAlignment(Pos.TOP_CENTER);
	}

	public int getWidth() {
		return width;
	}

	public void setWidth(int width) {
		this.width = width;
		resize();
	}

	public int getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
		resize();
	}

	public boolean isVerticallyCentered() {
		return verticallyCentered;
	}

	public void setVerticallyCentered(boolean verticallyCentered) {
		this.verticallyCentered = verticallyCentered;
		resize();
	}

	public boolean isHorizontallyCentered() {
		return horizontallyCentered;
	}

	public void setHorizontallyCentered(boolean horizontallyCentered) {
		this.horizontallyCentered = horizontallyCentered;
		resize();
	}

	public void setText(String text) {
		label.setText(text);
	}

	public boolean isEditable() {
		return editable;
	}

	public void setEditable(boolean editable) {
		this.editable = editable;

	}

	public void setPosition(int x, int y) {
		setTranslateX(x);
		setTranslateY(y);
	}

	@Override
	public void handle(MouseEvent event) {
		if (event.getClickCount() == 2) {

			if (!editable)
				return;

			textField.setText(label.getText());

			label.setVisible(false);

			// getChildren().add(textField);

			textField.setVisible(true);

			textField.setTranslateX(label.getTranslateX());

			if (verticallyCentered) {
				textField.setTranslateY(label.getTranslateY()
						+ label.getHeight() / 2 - 10);
			} else {
				textField.setTranslateY(label.getTranslateY());
			}

			textField.setMaxWidth(label.getMaxWidth());
			textField.setPrefWidth(label.getPrefWidth());

			textField.setMaxHeight(20);
			textField.setPrefHeight(20);

			textField.requestFocus();

			event.consume();

		}

	}

	public String getFieldName() {
		return fieldName;
	}

	public void setFieldName(String fieldName) {
		this.fieldName = fieldName;
	}

	public void setFieldNameEditing(String fieldName, boolean editable) {
		setFieldName(fieldName);
		setEditable(editable);
	}

	public void refreshModelGraphic() {
		CommonIdentified object = graphic.getSemantic();

		if (readScript != null) {

			Binding binding = new Binding();
			binding.setVariable("semantic", object);
			binding.setVariable("label", label);
			GroovyShell shell = new GroovyShell(binding);

			Object value = shell.evaluate(readScript);

			if (value instanceof String)
				label.setText((String) value);
			else
				label.setText(value.toString());

		} else if (fieldName != null) {

			try {
				Object value = util.getValue(object, fieldName);
				if (value instanceof String)
					label.setText((String) value);
				else
					label.setText(value.toString());
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public String getWriteScript() {
		return writeScript;
	}

	public void setWriteScript(String writeScript) {
		this.writeScript = writeScript;
	}

	public String getReadScript() {
		return readScript;
	}

	public void setReadScript(String readScript) {
		this.readScript = readScript;
	}

	public RefUtil getUtil() {
		return util;
	}

	public void setUtil(RefUtil util) {
		this.util = util;
	}

	public TextField getTextField() {
		return textField;
	}

	public void setTextField(TextField textField) {
		this.textField = textField;
	}

	public Label getLabel() {
		return label;
	}

	public void setLabel(Label label) {
		this.label = label;
	}

	public String getLeftPadding() {
		return leftPadding;
	}

	public void setLeftPadding(String leftPadding) {
		this.leftPadding = leftPadding;
	}

	public String getRightPadding() {
		return rightPadding;
	}

	public void setRightPadding(String rightPadding) {
		this.rightPadding = rightPadding;
	}

	public String getTopPadding() {
		return topPadding;
	}

	public void setTopPadding(String topPadding) {
		this.topPadding = topPadding;
	}

	public String getBottomPadding() {
		return bottomPadding;
	}

	public void setBottomPadding(String bottomPadding) {
		this.bottomPadding = bottomPadding;
	}

}
